perm filename SERVO.OLD[CMS,LCS]2 blob
sn#421899 filedate 1979-03-06 generic text, type T, neo UTF8
00100 TITLE SERVO
00200 .INSERT ASMBL.FAI[CMS,LCS]
00300
00400 ;I/O address definitions.
00500 DAC ← 100000 ;8 bit DAC.
00600 JCR ← 120000 ;Joint control output register.
00700 ENCL ← 140000 ;Encoder mux low.
00800 ENCH ← 140001 ;Encoder mux high.
00900
01000 STKSIZ ← 377 ;Stack size.
01200 LSBENB ← 40 ;Enable LSB servo.
01300
01400 ;Zero page variables.
01500 ;Not shared.
01600
01700 IOCTRL: 0 ;Copy of JCR output port.
01800 CURVEL: BLOCK 2 ;Current velocity.
01900 0 ;SETPT-1.
02000 SETPT: BLOCK 2 ;Current setpoint.
02100 0 ;SETINC-1.
02200 SETINC: BLOCK 2 ;Interpolating increment for setpoints.
02300 LSTINX: BLOCK 2 ;Position at last index pulse.
02400 OLDSP: BLOCK 2 ;Last commanded setpoint, for CMDVEL.
02500 POSERR: BLOCK 2 ;Current position error.
02600 DACSIG: BLOCK 2 ;Scratch.
02700
03000 INCTR: 0 ;Count the interpolations.
03100 HSTTMR: 0 ;Count ticks between host commands.
03200
03300 LOGTMP: BLOCK 4 ;Temp for the arithmetic routines.
03400
03500 ZAPEND ← .-1 ;Clear all the above in startup.
03600
03700 CURPOS: BLOCK 2 ;Current position, extended to 2 bytes.
03800
03900 TL: 0 ;Scratch for grey to binary.
04000 TH: 0
00100 ;Shared ram. Make all one byte values on odd addresses!
00200 LOC 200 ;Second half of zero page.
00300
00400 STATUS: BLOCK 2 ;Flags for the host.
00500 MODE: BLOCK 2 ;Mode bits from host.
00600
00700 CKWORD: BLOCK 2 ;Host I/O check/command word.
00800 CMDPOS: BLOCK 2 ;Commanded position from host.
00900
01000 BUSLO: 0 ;Buffer?
01100 BUSHI: 0
01200
01300 MEMPTR: BLOCK 2 ;Address pointer for diagnostic read.
01400 ;NINTER = function of INTSCL?
01500 NINTER: BLOCK 2 ;# of interpolations between position
01600 ;commands.
01700 INTSCL: BLOCK 2 ;# of bits to shift setpoint dif for
01800 ;interpolating.
01900 HSTLIM: BLOCK 2 ;# of clock ticks allowed between host
02000 ;commands.
02100 CMDVEL: BLOCK 2 ;Commanded velocity. Not shared?
02200 MASS: BLOCK 2 ;Inertia term for prediction.
02300 FRICTN: BLOCK 2 ;Viscous damping coefficient.
02400 GRAVTY: BLOCK 2 ;DC offset for gravity.
02500 POSTOL: BLOCK 2 ;Half-width of position tolerance band.
02600 INTTOL: BLOCK 2 ;Half-width of integration band.
02700
02800
02900 ;Start of prom.
03000 LOC 174000
03100
03200 INITBL: STATUS ↔ 200
03300 MODE ↔ 0
03400
03500 NINTER ↔ =32
03600 INTSCL ↔ 5
03700
03800 HSTLIM ↔ =48
03900 HSTLIM+1↔ 0 ;?
04300
04400 377
00100 ;Add SEI and CLI to all shared ram refs.
00200 ;Add ? for IOCTRL read?
00300 START: CLD
00400 LDXI STKSIZ ;Setup stack.
00500 TXS
00600
00700 ;Zero shared ram?
00800 LDAI 0
00900 LDXI ZAPEND
01000 RLOOP: STAZX 0 ;Reset ram.
01100 DEX
01200 BPL RLOOP
01400 STA DAC ;Clear DAC.
01500
01600 TAY
01700 BEQ RSTDEF ;Jump
01800
01900
02000 DLOOP: INY
02100 LDAY INITBL ;Init ram.
02200 STAZX 0
02300 INY
02400
02500 RSTDEF: LDXY INITBL
02600 CPXI 377
02700 BNE DLOOP
02800
02900 JSR POSUPD ;?
03000 JSR SETPOS ;?
03100
03200 CLI ;End of reset.
03300
03400 RSTCKW: LDAI 0 ;Reset check word.
03500 SEI
03600 STAZ CKWORD
03700 STAZ CKWORD+1
03800 CLI
03900 ;Idle loop. Wait for command.
04000 IDLE: LDXZ CKWORD+1;+1 for no lock.
04100 BEQ IDLE
04200
04300 SEI
04400 LDAZ CKWORD ;Get check word.
04500 LDXZ CKWORD+1
04600 CLI
04700
04800 ;CKWORD is command?
04900 SEI
05000 LDAZ CMDPOS ;Get position.
05100 LDXZ CMDPOS+1
05200 CLI
00100 ;Position command.
00200 CMDSRV: JSR ENBTST
00300 STAZ DACSIG
00400 STXZ DACSIG+1
00500
00600 SEC
00700 SBCZ SETPT
00800 STAZ SETINC
00900 TXA
01000 SBCZ SETPT+1
01100 LDXI 0
01200 STXZ SETPT-1
01300 STXZ SETINC-1
01400 LDXZ INTSCL
01500
01600 SCAL: CMPI 200 ;Extend sign.
01700 RORA
01800 RORZ SETINC
01900 RORZ SETINC-1
02000 DEX
02100 BNE SCAL
02200
02300 STAZ SETINC+1
02400 LDAZ NINTER
02500 STAZ INCTR
02600 SEC
02700 LDAZ DACSIG
02800 SBCZ OLDSP
02900 STAZ CMDVEL
03000 LDAZ DACSIG+1
03100 SBCZ OLDSP+1
03200 STAZ CMDVEL+1
03300 LDAZ DACSIG
03400 STAZ OLDSP
03500 LDAZ DACSIG+1
03600 STAZ OLDSP+1
03700
03800 LDAZ IOCTRL
03900 ORAI 44
04000 STAZ IOCTRL
04100 STA JCR ;Output it.
04200
04300 LDAZ HSTLIM ;Reset host timer.
04400 STAZ HSTTMR
04500 JMP CMDEND
00100 ;Clock tick interrupt.
00200 TICK: PHA ;Save state.
00300 TXA
00400 PHA
00500 TYA
00600 PHA
00700
00800 LDY ENCL ;Read encoder.
00900 LDA ENCH
01000
01100 ;Convert from grey to binary.
01200 STAZ TH
01300 LSRA
01400 EORZ TH
01500 STAZ TH
01600 TAX
01700
01800 TYA
01900 STAZ TL
02000 RORA
02100 EORZ TL
02200 STAZ TL
02300
02400 LSRZ TH
02500 RORA
02600 LSRZ TH
02700 RORA
02800
02900 EORZ TL
03000 STAZ TL
03100 TAY
03200 TXA
03300 EORZ TH
03400 STAZ TH
03500
03600 LSRA
03700 RORZ TL
03800 LSRA
03900 RORZ TL
04000 LSRA
04100 RORZ TL
04200 LSRA
04300 RORZ TL
04400
04500 EORZ TH
04600 STAZ TH
04700 TYA
04800 EORZ TL
04900 EORZ TH
05000 STAZ TL ;?
05100
05200 ;Extend sign from n bits?
05300 ; LDXZ TH ?
05400
05500 TAY ;?
05600 LDAZ TH ;?
00100 JSR POSUPD ;Put POSUPD here?
00200
00300 STAZ CURPOS
00400 STXZ CURPOS+1
00500
00600 DECZ HSTTMR
00700 BPL HOSTOK
00800
00900 LDAI 0
01000 STAZ HSTTMR
01100 STAZ CMDVEL
01200 STAZ CMDVEL+1
01300
01500 HOSTOK: LDAI 4
01600 BITZ IOCTRL ;If position mode is off,
01700 BNE INTRS
01800 JMP CURSRV ;don't servo?
01900
02000 ;Interpolate the setpoints.
02100 INTRS: CLC
02200 LDAZ SETPT-1
02300 ADCZ SETINC-1
02400 STAZ SETPT-1
02500 LDAZ SETPT
02600 ADCZ SETINC
02700 STAZ SETPT
02800 LDAZ SETPT+1
02900 ADCZ SETINC+1
03000 STAZ SETPT+1
03100
03200 DECZ INCTR
03300 BNE GPOSER
03400
03500 LDAI 0 ;Clear SETINC if done interpolating.
03600 STAZ SETINC-1
03700 STAZ SETINC
03800 STAZ SETINC+1
03900
04000 ;Calculate the position error.
04100 GPOSER: SEC
04200 LDAZ CURPOS
04300 SBCZ SETPT
04400 STAZ POSERR
04500 LDAZ CURPOS+1
04600 SBCZ SETPT+1
04700 STAZ POSERR+1
00100 BITZ MODE ;If servo is disabled, we're
00200 BPL OOTOL ;automatically out of tolerance
00300
00400 LDAZ POSERR+1;Test the sign of pos error.
00500 BMI NEGPER
00600
00700 LDAZ POSTOL ;Positive. Compare with tol.
00800 CMPZ POSERR
00900 LDAZ POSTOL+1
01000 SBCZ POSERR+1
01100 BCS TOLOK ;In tolerance.
01200 BCC OOTOL ;Jump.
01300
01400 NEGPER: CLC ;Negative. Add the tolerance.
01500 LDAZ POSTOL
01600 ADCZ POSERR
01700 LDAZ POSTOL+1
01800 ADCZ POSERR+1
01900 BCS TOLOK ;In tolerance.
02000
02100 OOTOL: LDAZ IOCTRL ;Out of tolerance.
02200 ANDI 177 ;Turn off the in tolerance
02300 BNE WCNTRL ;indicator.
02400
02500 TOLOK: LDAZ IOCTRL ;In tolerance. Turn it on.
02600 ORAI 200
02700 WCNTRL: STAZ IOCTRL
02800 STA JCR ;Copy it to output.
02900
03000 BITZ MODE ;If intergration is disabled,
03100 BVC OOBAND ;turn it off.
03200 LDAZ POSERR+1;Test sign of position error.
03300 BMI ADTOL
03400
03500 LDAZ INTTOL ;Positive. Compare with tol.
03600 CMPZ POSERR
03700 LDAZ INTTOL+1
03800 SBCZ POSERR+1
03900 BCS INBAND
04000 BCC OOBAND
04100
04200 ADTOL: CLC ;Negative. Add the tolerance.
04300 LDAZ INTTOL
04400 ADCZ POSERR
04500 LDAZ INTTOL+1
04600 ADCZ POSERR+1
04700 BCS INBAND
04800
04900 OOBAND: LDAZ IOCTRL ;Out of band. Turn off
05000 ORAI 10 ;integration by setting the
05100 ANDI 357 ;control bit. LSB servo off.
05200 BNE WCTRL2
00100 INBAND: LDAI LSBENB ;In band. Is LSB servo enabled
00200 BITZ MODE
00300 BEQ RCNTRL
00400
00500 LDAZ POSERR ;Yes. Is the error exactly 0?
00600 ORAZ POSERR+1
00700 BNE RCNTRL
00800
00900 LDAZ IOCTRL ;It is. Integration off, LSB
01000 ORAI 30 ;servo on.
01100 BNE WCTRL2 ;Jump.
01200
01300 RCNTRL: LDAZ IOCTRL ;LSB disabled or error
01400 ANDI 347 ;not zero. LSB servo off,
01500 ;integration on.
01600
01700 WCTRL2: STAZ IOCTRL
01800 STA JCR ;Output it.
00600 LDYZ CURVEL ;Get the velocity,
00700 LDAZ CURVEL+1
00800 JSR LOG
00900 LDXI FRICTN ;mult. by the friction
01100 JSR MULTIP ;coefficient,
01200 JSR EXP
01300
01400 TAX
01500 TYA
01600 CLC ;add the position error...
01700 ADCZ POSERR
01800 STAZ DACSIG
01900 TXA
02000 ADCZ POSERR+1
02100 STAZ DACSIG+1
02200 LDYI 0
02300 TXA ;(sign-extend the velocity)?
02400 BPL NODEY
02500 DEY
02600
02700 NODEY: CLC ;...and the gracity offset.
02800 LDAZ DACSIG
02900 SEI
03000 ADCZ GRAVTY
03100 TAY
03200 LDAZ GRAVTY+1
03250 CLI
03300 ADCZ DACSIG+1
03500 TAX ;?
03600
03700 JSR PUTDAC ;Put result out to the DAC.
03800 ;Put PUTDAC here? Not a subroutine?
04400
04500 CMDSP: ;Add deferred commands here?
00200 CMDEND: ;Done with commands?
00500
00600 INTXIT: PLA ;Restore state and dismiss interrupt.
00700 TAY
00800 PLA
00900 TAX
01000 PLA
01100 RTI
01200
01300 CURSRV: ;Not servoing ("Current mode")...
01400 ;Add stop mode?
01500 JMP CMDSP
01600
01700 INTBL: ;IMMEDIATE COMMAND TABLE?
01800 HCIRDM∧377 ;Read memory.
01900
02000 HCISRV∧377 ;Position mode?
02100
02200 CMTBL: ;DEFERRED COMMAND TABLE?
02300 CMDEND∧377 ;Read memory?
02400
02500 CMDSRV∧377 ;Position mode?
00100 ;Subroutines?
00200 ;Enter with position in A (low), X (middle), Y (high).
00300 ;Sets current position to that value, puts the setpoint
00400 ;to the same, clears the setpoint interpolating
00500 ;increment, and goes into stop mode?
00600 SETPOS: STAZ CURPOS ;Set the current position.
00700 STXZ CURPOS+1
00800
01100 STAZ SETPT ;Set the position command.
01200 STXZ SETPT+1
01300 STAZ OLDSP
01400 STXZ OLDSP+1
01500
01600 LDAI 75 ;I/O control bits for servo
01700 STAZ IOCTRL ;enable on, all others off.
01800 STA JCR
01900
02000 LDAI 0
02100 STAZ SETPT-1 ;Clear the setpoint extension
02200 STAZ SETINC-1;and the interpolator
02300 STAZ SETINC
02400 STAZ SETINC+1
02500 STAZ CMDVEL ;and the commanded velocity.
02600 STAZ CMDVEL+1
02700
02800 LDAZ SETPT ;Return the regs. unchanged.
02900 RTS
03000
03100 ;Enter with low counter value in Y.
03200 ;Returns updated position in A (low), X (middle),
03300 ;Y (high). Also sets CURVEL to the 16-bit signed
03400 ;velocity?
03600 POSUPD: STAZ DACSIG+1;Save high byte?
03700 TYA
03800 STAZ DACSIG ;Save that value.
03900 SEC
04000 SBCZ CURPOS ;Subtract the old position
04100 STAZ CURVEL ;yielding the velocity.
04200 LDAZ DACSIG+1
04300 SBCZ CURPOS+1
04400 STAZ CURVEL+1
04500 LDXZ CURPOS+1 ;Set up for updating bytes
04600 LDAZ DACSIG+1;Did bit 15 of pos. change?
04700 EORZ CURPOS+1
04800 BPL GETDAC ;If not, we're through.
04900 LDAZ CURVEL+1;It did. Which way did we move
05000 BMI DOWN
05100 LDAZ DACSIG+1;Upward.
05200 BMI GETDAC ;If bit 15 is on, we're done.
05300 INY ;Off. Increment high byte.
05400 JMP GETDAC
05500
05600 DOWN: LDAZ DACSIG+1;Downward.
05700 BPL GETDAC ;If bit 15 is off, we're done.
05800 DEY ;Decrement high byte.
05900
06000 GETDAC: LDAZ DACSIG
06100 RTS
00100 ;DAC output subroutine. Not sub?
00200 ;Enter with 3 byte value in Y (low), X (middle),
00300 ;A (high). Clobbers all registers, but the 8 bits the
00400 ;DAC got are returned in?
00500 PUTDAC: BMI NEGDAC ;Assuming the last I. loaded A.
00600 CPYI 200 ;Positive. Compare with 2↑7.
00700 BCS TOOHI
00800 CPXI 1
00900 SBCI 0
01000 BCC INRNGE
01100
01200 TOOHI: LDYI 177 ;Too high. Saturate positive.
01300 BNE INRNGE ;Jump.
01400
01500 NEGDAC: CPYI 200 ;Negative. Compare with -2↑7.
01600 BCC TOOLOW
01700
01800 CPXI 377
01900 SBCI 377
02000 BCS INRNGE
02100
02200 TOOLOW: LDYI 200 ;Too low. Saturate to -2↑7.
02300
02400 INRNGE: STY DAC ;Output 8 bits to the DAC.
02500 RTS
02600
02800 ENBTST: PHA ;Test for servo enabled?
02900 LDAZ MODE
03000 ANDI 202
03100 CMPI 200
03200 BNE NOTENB
03300 PLA ;OK. Return.
03400 RTS
03500
03600 NOTENB: PLA ;No. Wipe the return address and
03700 PLA ;end this command.
03800 PLA
03900 JMP CMDEND
00100 ;Arithmetic routines.
00200 ;Enter with high byte in A, low in Y.
00300 ;Returns A = characteristic and sign, Y = mantissa.
00400 ;Clobbers X, LOGTMP, LOGTMP+1.
00500 LOG: STYZ LOGTMP ;Save the inputs.
00600 STAZ LOGTMP+1
00700
00800 LDXI 20+100 ;?Init characteristic to 15.
00900 CMPI 0 ;Test sign of input.
01000 BPL POSIN
01100 SEC ;Negative. 2's complement it.
01200 LDAI 0
01300 SBCZ LOGTMP
01400 STAZ LOGTMP
01500 LDAI 0
01600 SBCZ LOGTMP+1
01700 POSIN: BNE NORML ;Is high byte zero?
01800 LDAZ LOGTMP ;Yes. Low byte?
01900 BEQ RTRN ;If so, return zero.
02000 LDYI 0 ;Low nonzero. Shift left one
02100 STYZ LOGTMP ;byte,
02200 LDXI 10+100 ;?change characteristic to 7.
02300 NORML: DEX ;Normalize the number, counting the
02400 ASLZ LOGTMP ;characteristic down. When the
02500 ROLA ;first "1" shifts out, we've subtracted
02600 BCC NORML ;1 from the normalized number
02700 ASLZ LOGTMP ;(This rounds the result)
02800 ADCI =11 ;and are left with the fraction
02900 TAY ;Adding 11 to that is equivalent to
03000 TXA ;adding 0.043.
03100 ADCI 0 ;Propagate the carry into the
03200 ;characteristic.
03300 ASLA ;Insert the sign bit from the saved
03400 ASLZ LOGTMP+1;input.
03500 RORA
03600 RTRN: RTS ;Done.
03700
03800 ;Enter with sign and characteristic in A, mantissa in Y
03900 ;Returns 16-bit integer, low byte in Y, high in A.
04000 ;Clobbers X, LOGTMP, LOGTMP+1.
04100 EXP: STAZ LOGTMP+1;Save sign of input.
04200 ANDI 177 ;Mask it off.
04300 BEQ ZEROIN ;Zero characteristic returns
04400 TAX ;zero.
04500 TYA ;Get the mantissa...
04600 SEC
04700 SBCI =11 ;...subtract 0.043...
04800 STAZ LOGTMP ;(save this value)
04900 TXA ;...propagate the carry and get rid
05000 SBCI 100 ;of the XS-64 offset.
05100 BMI NEGIN ;If negative (value < 1.0)
05200 ;return zero.
05300 CMPI =15 ;Test for overflow (value>=2↑15
05400 BCS SATUR
05500 TAX ;...no. Number is in range.
05600 ADCI -10 ;?Is characteristic below 8?
05700 BMI BLOATE
05800 TAX ;No. Reduce if by 8,
05900 JSR UNNORM ;unnormalize.
06000 BMI GETTMP ;Jump.
00100 BLOATE: JSR UNNORM ;Yes. Unnormalize, then
00200 ASLZ LOGTMP ;(round result)
00300 ADCI 0
00400 STAZ LOGTMP ;use result as low byte and
00500 LDAI 0 ;set high byte to zero.
00600
00700 GETTMP: LDYZ LOGTMP
00800 GTMP1: LDXZ LOGTMP+1;Test sign of input...
00900 BPL POSIGN
01000 STAZ LOGTMP+1;...negative. 2's complement
01100 LDAI 0 ;the result.
01200 SEC
01300 SBCZ LOGTMP
01400 TAY
01500 LDAI 0
01600 SBCZ LOGTMP+1
01700 POSIGN: RTS
01800
01900 NEGIN: LDAI 0 ;Set the result to zero if the
02000 ZEROIN: TAY ;input is negative.
02100 RTS
02200
02300 SATUR: LDYI 377 ;Saturate result to 2↑15 - 1 if
02400 STYZ LOGTMP ;input was 15 or more.
02500 LDAI 177
02600 BNE GTMP1 ;Jump.
02700
02800 UNNORM: LDAI 1 ;Unnormalize subroutine. Add 1
02900 BNE DECRX ;to the fraction.
03000
03100 SCALE: ASLZ LOGTMP ;Scale the fraction left by the
03200 ROLA ;amount of the characteristic.
03300 DECRX: DEX
03400 BPL SCALE
03500 RTS
03600
03700 ;Enter with characteristic of multiplier in A,
03800 ;mantissa in Y, X pointing to a pair of base page
03900 ;locations containing the multiplicand (mantissa in the
04000 ;low byte).
04100 ;Returns the product in A and Y, same form as the
04200 ;multiplier. Leaves X unchanged. Clobbers LOGTMP and
04300 ;LOGTMP+1.
04400 MULTIP: PHA
04500 EORZX 1 ;Compute sign of result,
04600 STAZ LOGTMP+1 ;save it away.
04700 PLA
04800 ANDI 177 ;Mask off multiplier sign.
04900 BEQ ZEROIN ;If zero, return zero.
05000 STAZ LOGTMP
05100 TYA ;Add the two logarithms.
05200 CLC
05300 ADCZX 0
05400 TAY
05500 LDAZX 1
05600 ANDI 177 ;If multiplicand is zero,
05700 BEQ ZEROIN ;return a zero.
05800 ADCZ LOGTMP
05900 SEC
06000 SBCI 100 ;Correct the XS-64 offset.
00100 BPL INSIGN ;Result in range?
00200 ANDI 100 ;No. If underflow,
00300 BNE NEGIN ;return zero.
00400 LDAI 177 ;Overflow. Saturate to
00500 LDYI 377 ;highest magnitude.
00600
00700 INSIGN: ASLA ;Insert the sign of the result.
00800 ASLZ LOGTMP+1
00900 RORA
01000 RTS
01100
01200 ;Inverse function: 2's complement the magnitude part
01300 ;of a 15-bit logarithm.
01400 ;Enter with characteristic in A, mantissa in Y.
01500 ;Returns inverse in the same form. X unchanged.
01600 ;Clobbers LOGTMP and LOGTMP+1.
01700 INV: STYZ LOGTMP ;Pretty straightforward...
01800 STAZ LOGTMP+1
01900 SEC
02000 LDAI 0 ;Complement the number by
02100 SBCZ LOGTMP ;subtracting it from zero.
02200 TAY
02300 LDAI 0
02400 SBCZ LOGTMP+1
02500 JMP INSIGN ;Insert the original sign.
02600
02700 ;DEFERRED COMMANDS.
02800
02900 LOC (.∨377)+1 ;For start of next page.
03000 DFBLK ← .
03100
03200 ;Set parameter command?
03300 CMDSET: STAZX 0 ;?
03400 JMP CMDEND
03500
03600 ;CMDCUR: Stop mode?
00100 ;Immediate commands.
00200
00300 LOC (.∨377)+1 ;For start of next page.
00400 IMBLK ← .
00500 HCISRV: ;?
00600
00700 ;Sync, ack?
00800 HCIRDM: LDYZ MEMPTR
00900 LDAY 0
01000 LDXY 1
01100 INY
01200 INY
01300 STYZ MEMPTR
01400
01500 STAZ BUSLO ;?
01600 STXZ BUSHI
01700 JMP INTXIT
01800
01900 ;Add HALVE to CURPOS. Fix CURPOS+2.
02000
02100 HCINOP: ;?
02200 ;Ack host.
02300 JMP INTXIT
02400
02500 NMI ← START ;Reset??
02600 ;Interrupt vectors.
02700 LOC 177772
02800 NMI∧377
02900 (NMI⊗-10)∧377
03000 START∧377
03100 (START⊗-10)∧377
03200 TICK∧377
03300 (TICK⊗-10)∧377
03400 END